﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Segex
{
    /// <summary>
    /// Encapsulates a string tuple used by the preprocess for replacements. Tuple<T1,T2> doesn't serialize easily."/>
    /// </summary>
    public class ReplacementMapping
    {
        public ReplacementMapping()
        {
            Source = string.Empty;
            Replacement = string.Empty;
        }

        public ReplacementMapping(string source, string replacement)
        {
            Source = source;
            Replacement = replacement;
        }

        public string Source { get; set; }
        public string Replacement { get; set; }
    }


    /// <summary>
    /// Basic preprocessor that only replaces stings. It's aware of quoted string literals and will skip these areas. 
    /// Avoids string.replace and associated GC chatter. Dictionaries are loaded from resource files for localisation 
    /// purposes.
    /// </summary>
    public class PreProcessor
    {


        private List<ReplacementMapping> replacements = new List<ReplacementMapping>();


        public PreProcessor()
        {
            //Only support English dictionary for now
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(replacements.GetType());
            replacements = (List<ReplacementMapping>)x.Deserialize(new StringReader(Resources.PPDictionary_en_US));
        }

        public string Preprocess(string input)
        {
            StringBuilder output = new StringBuilder(input.Length * 2);

            int c = 0;
            while (c < input.Length)
            {
                //If we're in a quoted context, skip it (for literals)
                if (input[c] == '"')
                {
                    output.Append('"'); c++;
                    while (c < input.Length && input[c] != '"') output.Append(input[c++]);
                    output.Append('"'); c++;
                    if (c >= input.Length)
                    {
                        break;
                    }

                }

                //Check for replacement string
                bool replaced = false;
                foreach (var replacement in replacements)
                {
                    if (string.Compare(replacement.Source, 0, input, c, replacement.Source.Length, true) == 0)
                    {

                        //Match, dump replacement and skip replaced
                        output.Append(replacement.Replacement);
                        c += replacement.Source.Length;
                        replaced = true;
                        break;
                    }
                }

                if (!replaced)
                {
                    //No replacement at this position, dump char and move on
                    output.Append(input[c++]);
                }


            }

            return output.ToString();

        }
    }

}
